import 'package:flutter/services.dart';
import 'package:lib_service/router_service.dart';

class RouterServiceImpl implements RouterService {
  final MethodChannel _channel = const MethodChannel('router-service');

  RouterServiceImpl() {
    _channel.setMethodCallHandler((MethodCall call) async {
      switch (call.method) {
        case 'handle':
          final arguments = Map<String, dynamic>.from(call.arguments);
          final url = arguments['url'] as String?;

          if (url == null) {
            return {"routeResult": RouteResult.error.index};
          }

          final params = arguments['params'] as Map<String, dynamic>?;

          RouteCompletion routeCompletion = await _handle(url, params: params);
          return {
            "routeResult": routeCompletion.result.index,
            "param": routeCompletion.param
          };

        default:
          return false;
      }
    });
  }

  @override
  Future<List<String>?> get urls async {
    return _channel.invokeListMethod<String>('urls');
  }

  @override
  RouterServiceDelegate? delegate;

  RouteCompletion? _makeRouteCompletion(dynamic value) {
    if (value == null) {
      return null;
    }

    final routeCompletion = Map<String, dynamic>.from(value);

    int? routeResult = routeCompletion['routeResult'] as int?;

    if (routeResult == null ||
        routeResult < 0 ||
        routeResult >= RouteResult.values.length) {
      return null;
    }

    return RouteCompletion(
        result: RouteResult.values[routeResult],
        param: routeCompletion['param']);
  }

  /// Push native page
  @override
  Future<RouteCompletion?> push(
    String url, {
    Map<String, dynamic>? params,
    bool animated = true,
  }) async {
    var arguments = {
      'url': url,
      'animated': animated,
    };

    if (params != null) {
      arguments["params"] = params;
    }

    dynamic routeCompletion = await _channel.invokeMethod('push', arguments);
    return _makeRouteCompletion(routeCompletion);
  }

  @override
  Future<bool?> pop(
      {int delta = 1, dynamic value, bool animated = true}) async {
    Map<String, dynamic> arguments = {
      'animated': animated,
      'delta': delta,
    };

    if (value != null) {
      arguments['value'] = value;
    }

    return _channel.invokeMethod<bool>('pop', arguments);
  }

  @override
  void finish({required List<String> urls}) async {
    _channel.invokeMethod('finish', urls);
  }

  /// Present native page
  @override
  Future<RouteCompletion?> present(
    String url, {
    Map<String, dynamic>? params,
    bool animated = true,
  }) async {
    var arguments = {
      'url': url,
      'animated': animated,
    };

    if (params != null) {
      arguments["params"] = params;
    }

    dynamic routeCompletion = await _channel.invokeMethod('present', arguments);
    return _makeRouteCompletion(routeCompletion);
  }

  @override
  Future<bool?> dismiss({dynamic value, bool animated = true}) async {
    Map<String, dynamic> arguments = {
      'animated': animated,
    };

    if (value != null) {
      arguments['value'] = value;
    }

    return _channel.invokeMethod<bool>('dismiss', arguments);
  }

  /// Run handler
  @override
  Future<RouteCompletion?> handle(
    String url, {
    Map<String, dynamic>? params,
  }) async {
    RouteCompletion routeCompletion = await _handle(url, params: params);

    if (routeCompletion.result == RouteResult.success) {
      return routeCompletion;
    }

    Map<String, dynamic> arguments = {
      'url': url,
      if (params != null) "params": params,
    };

    dynamic resultValue = await _channel.invokeMethod('handle', arguments);
    return _makeRouteCompletion(resultValue);
  }

  /// Run flutter handler
  Future<RouteCompletion> _handle(
    String url, {
    Map<String, dynamic>? params,
  }) async {
    final delegate = this.delegate;
    if (delegate == null) {
      return RouteCompletion(result: RouteResult.error, param: null);
    }

    return await delegate.handle(url: url, params: params);
  }

  @override
  Future<String?> alert(
      {String? title,
      required String message,
      String? confirmButtonText,
      bool interactive = false}) async {
    Map<String, dynamic> arguments = {
      'message': message,
      'interactive': interactive
    };

    if (title != null) {
      arguments['title'] = title;
    }

    if (confirmButtonText != null) {
      arguments['confirmButtonText'] = confirmButtonText;
    }

    return _channel.invokeMethod<String>('alert', arguments);
  }

  @override
  Future<String?> confirm(
      {String? title,
      required String message,
      String? confirmButtonText,
      String? cancelButtonText,
      bool interactive = false}) async {
    Map<String, dynamic> arguments = {
      'message': message,
      'interactive': interactive
    };

    if (title != null) {
      arguments['title'] = title;
    }

    if (confirmButtonText != null) {
      arguments['confirmButtonText'] = confirmButtonText;
    }

    if (cancelButtonText != null) {
      arguments['cancelButtonText'] = cancelButtonText;
    }

    return _channel.invokeMethod<String>('confirm', arguments);
  }

  @override
  Future<bool?> toast({required String message, bool interactive = false}) {
    Map<String, dynamic> arguments = {
      'message': message,
      'interactive': interactive
    };

    return _channel.invokeMethod<bool>('toast', arguments);
  }

  @override
  Future<bool?> loading(
      {required String message, bool interactive = true}) async {
    Map<String, dynamic> arguments = {
      'message': message,
      'interactive': interactive
    };

    return _channel.invokeMethod<bool>('loading', arguments);
  }

  @override
  Future<bool?> closeToast() async {
    return _channel.invokeMethod<bool>("closeToast");
  }
}
